package com.itcncp.wechat.app.search.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaMessage;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig;
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import com.itcncp.common.base.BaseController;
import com.itcncp.common.util.JsonUtils;
import com.itcncp.wechat.app.common.constant.ApiConstant;
import com.itcncp.wechat.app.common.constant.ApiResult;
import com.itcncp.wechat.app.common.constant.ApiResultConstant;
import com.itcncp.wechat.app.dao.model.UserCustomerInfo;
import com.itcncp.wechat.app.rpc.api.UserCustomerInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import me.chanjar.weixin.common.exception.WxErrorException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 *
 * Created by shuitcncp on 2016/12/10.
 */
@Controller
@RequestMapping("/wxmini")
@Api(tags = "微信小程序验证",value = "", description = "微信小程序验证", basePath = "/wxmini")

public class WxMiniController extends BaseController {


    private static final Logger LOGGER = LoggerFactory.getLogger( WxMiniController.class);

    @Autowired
    private UserCustomerInfoService userCustomerInfoService;

    /**
     *  监听小程序推送验证
     */
    @ResponseBody
    @ApiOperation(value="监听小程序推送验证",notes="监听小程序推送监听，验证加密信息")
    @RequestMapping(value = "/checkSignature", method = RequestMethod.GET)
    @ApiImplicitParams( value = {
            @ApiImplicitParam(paramType = "query", name = "signature", dataType = "String", required = false, value = "微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。"),
            @ApiImplicitParam(paramType = "query", name = "timestamp", dataType = "String", required = false, value = "时间戳"),
            @ApiImplicitParam(paramType = "query", name = "nonce", dataType = "String", required = false, value = "随机数"),
            @ApiImplicitParam(paramType = "query", name = "echostr", dataType = "String", required = false, value = "随机字符串")
    })
    public Object checkSignature(HttpServletRequest request,
                                     @RequestParam(required = false, value = "signature") String signature,
                                     @RequestParam(required = false, value = "timestamp") String timestamp,
                                     @RequestParam(required = false, value = "nonce") String nonce,
                                     @RequestParam(required = false, value = "echostr") String echostr) {

        System.err.println("监听小程序推送验证");

        //初始化配置
        WxMaInMemoryConfig wxMaInMemoryConfig = new WxMaInMemoryConfig();
        wxMaInMemoryConfig.setAppid(ApiConstant.WX_MINI_APPID);
        wxMaInMemoryConfig.setSecret(ApiConstant.WX_MINI_APPP_SECRET);
        wxMaInMemoryConfig.setToken(ApiConstant.WX_MINI_TOKEN);
        wxMaInMemoryConfig.setAesKey(ApiConstant.WX_MINI_ENCODING_AESKEY);
        WxMaConfig wxMaConfig = wxMaInMemoryConfig;

        WxMaService  wxMaService = new WxMaServiceImpl();
        wxMaService.setWxMaConfig(wxMaConfig);

        if(null != timestamp){
            if (!wxMaService.checkSignature(timestamp, nonce, signature)) {
                // 消息签名不正确，说明不是公众平台发过来的消息

                LOGGER.debug("2===>>非法请求","消息签名不正确，说明不是公众平台发过来的消息");
                System.err.println("2===>>非法请求 消息签名不正确，说明不是公众平台发过来的消息");
                return false;
            }
        }

        if (StringUtils.isNotBlank(echostr)) {

            LOGGER.debug("3===>>验证通过","说明是一个仅仅用来验证的请求，回显echostr"+echostr);
            System.err.println("3===>>验证通过  说明是一个仅仅用来验证的请求，回显echostr"+echostr);
            return echostr;
        }


        String encryptType = request.getParameter("encrypt_type");
        if(null == encryptType){
            return false;
        }
        final boolean isJson = Objects.equals(wxMaService.getWxMaConfig().getMsgDataFormat(), WxMaConstants.MsgDataFormat.JSON);
        if (StringUtils.isBlank(encryptType)) {
            LOGGER.debug("4===>>验证明文传输的消息",encryptType);
            System.err.println("4===>>验证明文传输的消息" + encryptType);
            // 明文传输的消息
            WxMaMessage inMessage;
            if (isJson){
                LOGGER.debug("4.1===>>验证明文传输的消息isJson",isJson);
                System.err.println("4.1===>>验证明文传输的消息isJson" + isJson);
                try {
                    inMessage = WxMaMessage.fromJson(IOUtils.toString(request.getInputStream(), String.valueOf(StandardCharsets.UTF_8)));
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }else {//xml

                LOGGER.debug("4.2===>>验证明文传输的消息xml",isJson);
                System.err.println("4.2===>>验证明文传输的消息isJson" + isJson);
                try {
                    inMessage = WxMaMessage.fromXml(request.getInputStream());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            LOGGER.debug("4.3===>>验证通过",isJson);
            System.err.println("4.3===>>验证通过" + isJson);
            return true;
        }

        if ("aes".equals(encryptType)) {

            LOGGER.debug("5===>>验证加密传输的消息",encryptType);
            System.err.println("5===>>验证加密传输的消息" + encryptType);
            // 是aes加密的消息
            String msgSignature = request.getParameter("msg_signature");
            WxMaMessage inMessage;
            if (isJson) {

                LOGGER.debug("5.1===>>验证明文传输的消息isJson",isJson);
                System.err.println("5.1===>>验证明文传输的消息isJson" + isJson);
                try {
                    inMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(),wxMaService.getWxMaConfig());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {//xml
                LOGGER.debug("5.2===>>验证明文传输的消息isJson",isJson);
                System.err.println("5.2===>>验证明文传输的消息isJson" + isJson);
                try {
                    inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), wxMaService.getWxMaConfig(), timestamp, nonce, msgSignature);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

//            wxMaService.getWxMaMessageRouter().route(inMessage);
            return true;
        }


        LOGGER.debug("6===>>不可识别的加密类型",isJson);
        System.err.println("6===>>不可识别的加密类型" + isJson);
        return false;

    }


    @ResponseBody
    @ApiOperation(value="获取用户openid",notes="根据用户code获取openid")
    @RequestMapping(value = "/openid", method = RequestMethod.GET)
    @ApiImplicitParams( value = {
            @ApiImplicitParam(paramType = "query", name = "jsCode", dataType = "String", required = true, value = "前端传输code")
    })
    public Object openid(HttpServletRequest request,
                                 @RequestParam(required = false, value = "jsCode") String jsCode) {


            System.err.println("微信认证获取jsCode================="+jsCode);
        //初始化配置
        WxMaInMemoryConfig wxMaInMemoryConfig = new WxMaInMemoryConfig();
        wxMaInMemoryConfig.setAppid(ApiConstant.WX_MINI_APPID);
        wxMaInMemoryConfig.setSecret(ApiConstant.WX_MINI_APPP_SECRET);
        wxMaInMemoryConfig.setToken(ApiConstant.WX_MINI_TOKEN);
        wxMaInMemoryConfig.setAesKey(ApiConstant.WX_MINI_ENCODING_AESKEY);
        WxMaConfig wxMaConfig = wxMaInMemoryConfig;

        WxMaService wxMaService = new WxMaServiceImpl();
        wxMaService.setWxMaConfig(wxMaConfig);

        try {
            wxMaService.getAccessToken();
        } catch (WxErrorException wxtoken) {

            try {
                wxMaService.getAccessToken(true);
            } catch (WxErrorException e) {

                System.err.println("获取微信token失败============="+e.getError());

                return new ApiResult(ApiResultConstant.FAILED,wxtoken.getMessage());
            }
        }


        //根据用户code获取用户信息
        WxMaJscode2SessionResult wxMaJscode2SessionResult = null;
        try {
            wxMaJscode2SessionResult = wxMaService.getUserService().getSessionInfo(jsCode);
        } catch (WxErrorException ex) {
            return new ApiResult(ApiResultConstant.FAILED,ex.getMessage());
        }

        System.err.println("获取微信认证信息============="+JsonUtils.toJson(wxMaJscode2SessionResult));

        if(null != wxMaJscode2SessionResult){

            System.err.println("获取微信OPENID============="+wxMaJscode2SessionResult.getOpenid());

            return new ApiResult(ApiResultConstant.SUCCESS,wxMaJscode2SessionResult);
        }


        return new ApiResult(ApiResultConstant.FAILED);

    }


    @ResponseBody
    @ApiOperation(value="解密用户敏感数据",notes="解密用户敏感数据")
    @RequestMapping(value = "/getWxMiniUserInfo", method = RequestMethod.GET)
    @ApiImplicitParams( value = {
            @ApiImplicitParam(paramType = "query", name = "sessionKey", dataType = "String", required = true, value = "会话密钥"),
            @ApiImplicitParam(paramType = "query", name = "encryptedData", dataType = "String", required = true, value = "消息密文"),
            @ApiImplicitParam(paramType = "query", name = "ivStr", dataType = "String", required = true, value = "加密算法的初始向量")
    })
    public Object getWxMiniUserInfo(HttpServletRequest request,
                                    @RequestParam(required = true, value = "sessionKey") String sessionKey,
                                    @RequestParam(required = true, value = "encryptedData") String encryptedData,
                                    @RequestParam(required = true, value = "ivStr") String ivStr) throws WxErrorException {



        //初始化配置
        WxMaInMemoryConfig wxMaInMemoryConfig = new WxMaInMemoryConfig();
        wxMaInMemoryConfig.setAppid(ApiConstant.WX_MINI_APPID);
        wxMaInMemoryConfig.setSecret(ApiConstant.WX_MINI_APPP_SECRET);
        wxMaInMemoryConfig.setToken(ApiConstant.WX_MINI_TOKEN);
        wxMaInMemoryConfig.setAesKey(ApiConstant.WX_MINI_ENCODING_AESKEY);
        WxMaConfig wxMaConfig = wxMaInMemoryConfig;

        WxMaService wxMaService = new WxMaServiceImpl();
        wxMaService.setWxMaConfig(wxMaConfig);

        //根据用户code获取用户信息
        WxMaUserInfo wxMaUserInfo = wxMaService.getUserService().getUserInfo(sessionKey,encryptedData,ivStr);

        if(null != wxMaUserInfo){
            return new ApiResult(ApiResultConstant.SUCCESS,wxMaUserInfo);
        }


        return new ApiResult(ApiResultConstant.FAILED);

    }

    @ResponseBody
    @ApiOperation(value="获取小程序码",notes="通过该接口生成的小程序码，永久有效，数量暂无限制。" +
            " 用户扫描该码进入小程序后，将统一打开首页，开发者需在对应页面根据获取的码中 scene 字段的值，再做处理逻辑。" +
            " 使用如下代码可以获取到二维码中的 scene 字段的值。 调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟，" +
            " 开发工具模拟时的 scene 的参数值需要进行 urlencode")
    @RequestMapping(value = "/createWxCodeLimit", method = RequestMethod.GET)
    @ApiImplicitParams( value = {
            @ApiImplicitParam(paramType = "query", name = "scene", dataType = "String", required = true,
                    value = "最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~，" +
                            "其它字符请自行编码为合法字符（因不支持%，中文无法使用 urlencode 处理，请使用其他编码方式）"),
            @ApiImplicitParam(paramType = "query", name = "page", dataType = "String", required = true,
                    value = "必须是已经发布的小程序页面，例如 \"pages/index/index\" ,如果不填写这个字段，默认跳主页面")
    })
    public Object getWxMiniUserInfo(HttpServletRequest request,
                                    @RequestParam(required = true, value = "scene") String scene,
                                    @RequestParam(required = true, value = "page") String page) throws WxErrorException {



        //初始化配置
        WxMaInMemoryConfig wxMaInMemoryConfig = new WxMaInMemoryConfig();
        wxMaInMemoryConfig.setAppid(ApiConstant.WX_MINI_APPID);
        wxMaInMemoryConfig.setSecret(ApiConstant.WX_MINI_APPP_SECRET);
        wxMaInMemoryConfig.setToken(ApiConstant.WX_MINI_TOKEN);
        wxMaInMemoryConfig.setAesKey(ApiConstant.WX_MINI_ENCODING_AESKEY);
        WxMaConfig wxMaConfig = wxMaInMemoryConfig;

        WxMaService wxMaService = new WxMaServiceImpl();
        wxMaService.setWxMaConfig(wxMaConfig);

        //根据用户code获取用户信息
        File wxQrcodeImg = wxMaService.getQrcodeService().createWxCodeLimit(scene,page,1,true,null);

        if(null != wxQrcodeImg){

            //上传到阿里云

            return new ApiResult(ApiResultConstant.SUCCESS,wxQrcodeImg);
        }


        return new ApiResult(ApiResultConstant.FAILED);

    }



    @ResponseBody
    @ApiOperation(value="发送充值交易模板消息",notes="发送模板消息")
    @RequestMapping(value = "/sendTemplateMsg", method = RequestMethod.GET)
    @ApiImplicitParams( value = {
            @ApiImplicitParam(paramType = "query", name = "userId", dataType = "Long", required = true, value = "用户ID"),
            @ApiImplicitParam(paramType = "query", name = "fromid", dataType = "String", required = true, value = "fromid")
    })
    public Object sendTemplateMsg(HttpServletRequest request,
                                  @RequestParam(required = true,defaultValue = "",value = "userId") Long userId,
                         @RequestParam(required = true,  value = "fromid") String fromid) {




        //String toUser, String templateId, String page, String formId, List<WxMaTemplateMessage.Data> data, String color, String emphasisKeyword

        UserCustomerInfo userCustomerInfo = userCustomerInfoService.selectByPrimaryKey(userId);

        if(null == userCustomerInfo){
            return new ApiResult( ApiResultConstant.FAILED);
        }

        //接收者（用户）的 openid
        String openid = userCustomerInfo.getDeviceAppNo();
        //所需下发的模板消息的id
        String templateId = ApiConstant.WX_MINI_NOTICE_PAY;
        //点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转。
        String page ="index?foo=trans";
        String formId =fromid; //表单提交场景下，为 submit 事件带上的 formId；支付场景下，为本次支付的 prepay_id
        //模板内容字体的颜色，不填默认黑色
        String color = "";
        String emphasis_keyword = ""; //模板需要放大的关键词，不填则默认无放大

        WxMaTemplateMessage wxMaTemplateMessage = new WxMaTemplateMessage();
        List<WxMaTemplateMessage.Data> tempData = new ArrayList<WxMaTemplateMessage.Data>();

        tempData.add(new WxMaTemplateMessage.Data("keyword1","京A12345"));
        tempData.add(new WxMaTemplateMessage.Data("keyword2","50 元"));
        tempData.add(new WxMaTemplateMessage.Data("keyword3","已支付"));
        tempData.add(new WxMaTemplateMessage.Data("keyword4","G121009831201803291202331"));
        tempData.add(new WxMaTemplateMessage.Data("keyword5","出口收费站：京通八里桥"));
        tempData.add(new WxMaTemplateMessage.Data("keyword6","欢迎使用ITC不停车收费。如对订单有疑问，请在30分钟后联系客服！"));

        wxMaTemplateMessage.setToUser(openid);
        wxMaTemplateMessage.setTemplateId(templateId);
        wxMaTemplateMessage.setPage(page);
        wxMaTemplateMessage.setFormId(formId);
        wxMaTemplateMessage.setEmphasisKeyword(emphasis_keyword);
        wxMaTemplateMessage.setColor(color);
        wxMaTemplateMessage.setData(tempData);

        //初始化配置
        WxMaInMemoryConfig wxMaInMemoryConfig = new WxMaInMemoryConfig();
        wxMaInMemoryConfig.setAppid(ApiConstant.WX_MINI_APPID);
        wxMaInMemoryConfig.setSecret(ApiConstant.WX_MINI_APPP_SECRET);
        wxMaInMemoryConfig.setToken(ApiConstant.WX_MINI_TOKEN);
        wxMaInMemoryConfig.setAesKey(ApiConstant.WX_MINI_ENCODING_AESKEY);
        WxMaConfig wxMaConfig = wxMaInMemoryConfig;

        WxMaService wxMaService = new WxMaServiceImpl();
        wxMaService.setWxMaConfig(wxMaConfig);

        //发送支付订单
        try {
            wxMaService.getMsgService().sendTemplateMsg(wxMaTemplateMessage);
        } catch (WxErrorException e) {
            System.err.println("推送失败~~");
            return new ApiResult(ApiResultConstant.FAILED,e.getError());
        }

        return new ApiResult(ApiResultConstant.SUCCESS,wxMaTemplateMessage);

    }
}